package com.gitee.wsl.markdown.html


abstract class HtmlTagImpl(
    val name: String,
    val start: Int,
    val attributes: Map<String, String>
) : HtmlTag {
    var end: Int = HtmlTag.NO_END
    override fun name(): String {
        return name
    }

    override fun start(): Int {
        return start
    }

    override fun end(): Int {
        return end
    }

    override val isEmpty: Boolean
        get() = start == end

    override fun attributes(): Map<String, String> {
        return attributes
    }

    override val isClosed: Boolean
        get() = end > HtmlTag.NO_END



    class InlineImpl(name: String, start: Int, attributes: Map<String, String>) :
        HtmlTagImpl(name, start, attributes), HtmlTag.Inline {
        override fun closeAt(end: Int) {
            if (!isClosed) {
                super.end = end
            }
        }

        override fun toString(): String {
            return "InlineImpl{" +
                    "name='" + name + '\'' +
                    ", start=" + start +
                    ", end=" + end +
                    ", attributes=" + attributes +
                    '}'
        }

        override val isInline: Boolean
            get() = true
        override val isBlock: Boolean
            get() = false
        override val asInline: HtmlTag.Inline
            get() =this
        override val asBlock: HtmlTag.Block
            get() =  throw ClassCastException("Cannot cast Inline instance to Block")

    }

    class BlockImpl(
        name: String,
        start: Int,
        attributes: Map<String, String> = emptyMap(),
        val parent: BlockImpl? = null
    ) : HtmlTagImpl(name, start, attributes), HtmlTag.Block {
        var children= mutableListOf<HtmlTag>()
        override fun closeAt(end: Int) {
            if (!isClosed) {
                super.end = end
                children.forEach {
                    it.closeAt(end)
                }
            }
        }

        override val isRoot: Boolean
            get() = parent == null

        override fun parent(): HtmlTag.Block? {
            return parent
        }

        override fun children(): List<HtmlTag> {
            return children
        }

        override fun attributes(): Map<String, String> {
            return attributes
        }

        override val isInline: Boolean
            get() = false
        override val isBlock: Boolean
            get() = true
        override val asInline: HtmlTag.Inline
            get() = throw ClassCastException("Cannot cast Inline instance to Block")
        override val asBlock: HtmlTag.Block
            get() =  this

        override fun toString(): String {
            return "BlockImpl{" +
                    "name='" + name + '\'' +
                    ", start=" + start +
                    ", end=" + end +
                    ", attributes=" + attributes +
                    ", parent=" + parent?.name +
                    ", children=" + children +
                    '}'
        }

        companion object {
            fun root(): BlockImpl {
                return BlockImpl("", 0)
            }

            fun create(
                name: String,
                start: Int,
                attributes: Map<String, String>,
                parent: BlockImpl?
            ): BlockImpl {
                return BlockImpl(name, start, attributes, parent)
            }
        }
    }
}